<?php
/**
 * @property Status $Status
 * @property Author $Author
 * @property JobType $JobType
 * @property JobVersionName $JobVersionName
 * @property JobVersionComment $JobVersionComment
 * @property CudaJob $CudaJob
 * @property ParamFdk $ParamFdk
 * @property ParamSirt $ParamSirt
 * @property ParamImageComproiType $ParamImageComproiType
 * @property ParamImageType        $ParamImageType
 * @property ParamImageClip        $ParamImageClip        
 * @property ParamImageIndir       $ParamImageIndir
 * @property ParamImageOutdir      $ParamImageOutdir
 * @property ParamImageRoiZ        $ParamImageRoiZ
 * @property ParamProjOutdir       $ParamProjOutdir
 * @property ParamProjGaussSigma   $ParamProjOutdir
 * @property ParamMisclImgYpad     $ParamMisclImgYpad
 * @property ParamMisclBwZmult     $ParamMisclBwZmult
 * @property ParamMisclBwYmult     $ParamMisclBwYmult
 */
class JobVersion extends AppModel {
	
  var $name = 'JobVersion';
	var $displayField = 'version_num';
  
  // These must be set so that AppModel::removeBlankOptionalFields()  can do it's job.
  //   (this is inherited from AppModel)
  //  Note: 'ParamProjGaussSigma'=>'gauss_sigma' gets added dynamcially if 'Apply Gaussian Filter'
  //  is not checked by the user
  var $optionalAssocModelsAndFields = array('JobVersionName'   =>'name', 
                                            'JobVersionComment'=>'comment',
                                            'ParamImageIndir'  =>'indir',
                                            'ParamImageOutdir' =>'outdir',
                                            'ParamImageRoiZ'   =>array('roi_z_0','roi_z_1'),
                                            'ParamProjOutdir'  =>'outdir',
                                            'ParamMisclBwYmult'=>'bw_ymult',
                                            'ParamMisclBwZmult'=>'bw_zmult',
                                            'ParamMisclImgYpad'=>'img_ypad',
                                            'ParamImageClip'   =>array('clipmin', 'clipmax'),
                                            'ParamImageZ'      =>array('out_z_0','out_z_1'),
                                            ); // 
	// Default for all data related to a new JobVersion (including related tables). 
  // These will be used if user wants to create a new Job, but does not want 
  // to use a 'template'.
  var $defaults = array(
      'JobVersion'    => array(
          'status_id'     => 1, // "Prepared"
          'param_image_nx'=> 0,
          'param_image_ny'=> 0,
          'param_image_nz'=> 0,
          'param_image_comproi_type_id'=>1, // "Bbox"
          //'param_image_type_id' =>  ,
          'param_image_foa_threshold'  =>0.0,
          'param_image_foa_outsidemax' =>0.0,
          // 2 Voxel types:
          'param_image_dxy'            =>0.0,
          'param_image_dz'             =>0.0,
          
          'param_proj_step'            =>1,
          'param_proj_indir'           =>"../projdata",          
          
      ),
      'ParamImageRoiZ'=> array(
          'roi_z_0'=>1,
          'roi_z_1'=>-1,
      ),
      'ParamProjGaussSigma'=> array(
          'gauss_sigma'=>2.0
      ),
      'ParamMisclBwYmult'  => array(
          'bw_ymult'=>3
      ),
      'ParamMisclBwZmult'  => array(
          'bw_zmult'=>3
      ),
      'ParamMisclImgYpad'  => array(
          'img_ypad'=>0
      ),
      
      'ParamSirtBasis'  => array(
          'alpha'     =>1.0,
          'niter'     =>1,
          'nsubs'     =>1,
          'sirt_subset_mode_x_id'=>3, // "Orthogonal + Furthest Tie Breaker"
          'sirt_subset_mode_y_id'=>2, // "Wheelspoke"
      ),
      'ParamFdkBasis'  => array(
          'alpha'     =>1.0,
          'param_fdk_filter_id' =>1, // "Ramp"
      ),
      'ParamImageClip' => array(
          'clipmin'  =>0.0,
          'clipmax' =>0.0
      ),
      'ParamImageZ' => array(
          'out_z_0'  => -1,
          'out_z_1'  => -1
      ),
      'ParamImageOutdir' => array(
          'outdir'  => 'recon'
      )
  );
  
  
  var $validate = array(
    // <editor-fold defaultstate="collapsed" desc="'validate' array">    
    'job_type_id' => array(
        'notempty' => array(
          'rule' => array('notempty'),
          'message' => 'You must choose a Job Type, partner.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
    ),
    // TODO:  should author_id and status_id also have a 'notempty' rule?
      
    // <image> params
    'param_image_nx' => array(
        'numeric' => array(
          'rule' => array('numeric'),
          //'message' => 'Your custom message here',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'integerRange' => array(
            'rule' => array('validateIntRange', 'param_image_nx', 0, NULL),
            'message' => 'Value must be an integer, 0 or greater.'
        )
		),
    'param_image_ny' => array(
        'numeric' => array(
          'rule' => array('numeric'),
          //'message' => 'Your custom message here',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'integerRange' => array(
            'rule' => array('validateIntRange', 'param_image_ny', 0, NULL),
            'message' => 'Value must be an integer, 0 or greater.'
        )
		),
    'param_image_nz' => array(
        'numeric' => array(
          'rule' => array('numeric'),
          //'message' => 'Your custom message here',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'integerRange' => array(
            'rule' => array('validateIntRange', 'param_image_nz', 0, NULL),
            'message' => 'Value must be an integer, 0 or greater.'
        )
		),         
    'param_image_comproi_type_id' => array(
        'notempty' => array(
          'rule' => array('notempty'),
          'message' => 'This value cannot be empty.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
    ), 
    'param_image_type_id' => array(
        'notempty' => array(
          'rule' => array('notempty'),
          'message' => 'This value cannot be empty.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
    ),       
    'param_image_foa_threshold' => array(
        'numeric' => array(
          'rule' => array('numeric'),
          'message' => 'Value must be a real number.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
    ),      
    'param_image_foa_outsidemax' => array(
        'numeric' => array(
          'rule' => array('numeric'),
          'message' => 'Value must be a real number.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
    ),   
    'param_image_dxy' => array(
        'numeric' => array(
            'rule' => array('numeric'),
            'message' => 'Value must be a real number.',
            //'allowEmpty' => false,
            //'required' => false,
            //'last' => false, // Stop validation after this rule
            //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'range' => array(
            'rule' => array('validateRange', // Custom func to do validation: uses app_model::validateRange() 
                            'param_image_dxy',  // field to validate
                             0,       // lower bound
                             null,    // upper bound
                             true,   // lowerBoundIsOK  
                             false),  // upperBoundIsOK  
            'message' => 'Value must be 0 or greater.',
        ),
    ),        
    'param_image_dz' => array(
        'numeric' => array(
          'rule' => array('numeric'),
          'message' => 'Value must be a real number.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'range' => array(
            'rule' => array('validateRange', // Custom func to do validation: uses app_model::validateRange() 
                            'param_image_dz',  // field to validate
                             0,       // lower bound
                             null,    // upper bound
                             true,   // lowerBoundIsOK  
                             false),  // upperBoundIsOK  
            'message' => 'Value must be 0 or greater.',
        ),
    ),
    // <proj> params
    'param_proj_indir' => array(
        'notempty' => array(
          'rule' => array('notempty'),
          'message' => 'This value cannot be empty.',
          //'allowEmpty' => false,
          //'required' => false,
          //'last' => false, // Stop validation after this rule
          //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'maxlength' => array(
            'rule' => array('maxlength', 256),
            'message' => 'Maximum length of this field is 256 characters.',
            //'allowEmpty' => false,
            //'required' => false,
            //'last' => false, // Stop validation after this rule
            //'on' => 'create', // Limit validation to 'create' or 'update' operations
        )
		),  
		'param_proj_step' => array(
        'numeric' => array(
            'rule' => array('numeric'),
            //'message' => 'Your custom message here',
            //'allowEmpty' => false,
            //'required' => false,
            //'last' => false, // Stop validation after this rule
            //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
        'integerRange' => array(
            'rule' => array('validateIntRange', 'param_proj_step', 1, NULL),
            'message' => 'Value must be an integer, 1 or greater.'
        )
		),
    'param_proj_apply_medianfilter' => array( // http://book.cakephp.org/view/1152/Core-Validation-Rules
        'rule' => array('boolean'),        
        'message' => 'This value must be a boolean.'    
    ),
    'param_proj_apply_gaussianfilter' =>  array( // http://book.cakephp.org/view/1152/Core-Validation-Rules
        'rule' => array('boolean'),        
        'message' => 'This value must be a boolean.'    
    ),
    'param_proj_apply_downsampling' => array( // http://book.cakephp.org/view/1152/Core-Validation-Rules
        'rule' => array('boolean'),        
        'message' => 'This value must be a boolean.'    
    ),
    // <miscl> param
    'param_miscl_reserror' => array( // http://book.cakephp.org/view/1152/Core-Validation-Rules
        'rule' => array('boolean'),        
        'message' => 'This value must be a boolean.'    
    ), 
	); //////////////// end validate array //////////////////   // </editor-fold>


  // <editor-fold defaultstate="collapsed" desc="Associations">
  // ASSOCIATIONS
  //The Associations below have been created with all possible keys, those that are not needed can be removed
  // <editor-fold defaultstate="collapsed" desc="hasOne associations">
	var $hasOne = array(
		'CudaJob' => array(
        'className' => 'CudaJob',
        'foreignKey' => 'job_version_id',
        'dependent'  => true,  // When a 'job version' gets deleted, also delete it's CudaJob
                                    //  (be sure the 'cascade' option is set to true in the delete()
                                    //   call [it is by default])
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
		'JobVersionName' => array(
        'className' => 'JobVersionName',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete it's Name  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
		'ParamFdk' => array(
        'className' => 'ParamFdk',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
		'ParamSirt' => array(
        'className' => 'ParamSirt',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
    // <image> params
    'ParamImageIndir' => array(
        'className' => 'ParamImageIndir',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
    'ParamImageOutdir' => array(
        'className' => 'ParamImageOutdir',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
    'ParamImageRoiZ' => array(
        'className' => 'ParamImageRoiZ',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		), 
    'ParamImageClip' => array(
        'className' => 'ParamImageClip',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		), 
    'ParamImageZ' => array(
        'className' => 'ParamImageZ',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
    // <miscl> params  
    'ParamMisclBwYmult' => array(
        'className' => 'ParamMisclBwYmult',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),       
    'ParamMisclBwZmult' => array(
        'className' => 'ParamMisclBwZmult',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		), 
    'ParamMisclImgYpad' => array(
        'className' => 'ParamMisclImgYpad',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		), 
    // <proj> params  
    'ParamProjGaussSigma' => array(
        'className' => 'ParamProjGaussSigma',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),       
    'ParamProjOutdir' => array(
        'className' => 'ParamProjOutdir',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete this  
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),    
	); // end hasOne associations </editor-fold>
  // <editor-fold defaultstate="collapsed" desc="belongsTo associations">
	var $belongsTo = array(
		'Job' => array(
        'className' => 'Job',
        'foreignKey' => 'job_id',
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
		'Status' => array(
        'className' => 'Status',
        'foreignKey' => 'status_id',
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
		'Author' => array(
        'className' => 'Author',
        'foreignKey' => 'author_id',
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
		'JobType' => array(
        'className' => 'JobType',
        'foreignKey' => 'job_type_id',
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
    // <image> params
    'ParamImageComproiType' => array(
        'className' => 'ParamImageComproiType',
        'foreignKey' => 'param_image_comproi_type_id',
        'conditions' => '',
        'fields' => '',
        'order' => ''
		),
    'ParamImageType' => array(
        'className' => 'ParamImageType',
        'foreignKey' => 'param_image_type_id',
        'conditions' => '',
        'fields' => '',
        'order' => ''
    ),  
	);  // </editor-fold>

	var $hasMany = array(
		'JobVersionComment' => array(
        'className' => 'JobVersionComment',
        'foreignKey' => 'job_version_id',
        'dependent'    => true,   // When a JobVersion gets deleted, also delete these comments  
        //'dependent' => false,
        'conditions' => '',
        'fields' => '',
        'order' => '',
        'limit' => '',
        'offset' => '',
        'exclusive' => '',
        'finderQuery' => '',
        'counterQuery' => ''
		)
	);
  // </editor-fold>
  
  /**
   *
   * @param int $job_id
   * @return int
   */
  function findNextVersionNum($job_id) {
   
    // We want to find the versions that belong to this Job. Order them based on version_num
    // in descending order so we can just take the first one to get the highest version_num.
    $conditions = array('job_id' => $job_id);
    $fields     = array('JobVersion.version_num');
    $order      = 'version_num desc';
    
    $this->recursive = -1;
    $foundArray = $this->find('first', array('conditions'=>$conditions,
                                             'fields'    =>$fields,
                                             'order'     =>$order ));
    //debug("previous high num: "); debug($foundArray);
    return ($foundArray['JobVersion']['version_num'] +1);
    
  } //////// end findNextVersionNum() ///////////////
  
  
  
} /////////////////////////////// end class /////////////////////////////////////////////
